﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using XNA_Game_Engine.Common;
using System;
using System.IO;

namespace XNA_Game_Engine.Map
{   
    class IsometricTilemap
    {
        private float x, y;
        private int[,] mapLayer1;
        private int[,] mapLayer2;
        private int[,] mapLayer3;
        private int width, height, tileWidth, tileHeight, tilesPerRow, tileOffset;
        private Texture2D tileset;


        public IsometricTilemap( int tileWidth, int tileHeight, int mapWidth, int mapHeight, Texture2D tileset )
        {
            x = (GameProperties.ScreenWidth/2.0f)/2.0f;
            y = GameProperties.ScreenHeight/2.0f;
            this.tileWidth = tileWidth;
            this.tileHeight = tileHeight;
            width = mapWidth;
            height = mapHeight;
            this.tileset = tileset;
            tilesPerRow = tileset.Width/tileWidth;

            mapLayer1 = new int[height,width];
            mapLayer2 = new int[height, width];
            mapLayer3 = new int[height, width];

            tileOffset = 9;

            ResetMap();
        }


        public IsometricTilemap(  String filename, Texture2D tileset )
        {
            this.tileset = tileset;
            x = (GameProperties.ScreenWidth / 2.0f) / 2.0f;
            y = GameProperties.ScreenHeight / 2.0f;

            LoapMapFromFile(filename);
            tilesPerRow = tileset.Width / tileWidth;
        }


        private void LoapMapFromFile(String filename)
        {
            TextReader buffer = new StreamReader(filename);

            String data = buffer.ReadLine();

            data = buffer.ReadLine();
            String[] mapDimensionData = data.Split(' ');
            width = int.Parse(mapDimensionData[0]);
            height = int.Parse(mapDimensionData[1]);
            System.Diagnostics.Debug.WriteLine( "Map Width: " + width + "| Map Height: " + height );

            data = buffer.ReadLine();
            String[] tileDimensionData = data.Split(' ');
            tileWidth = int.Parse(tileDimensionData[0]);
            tileHeight = int.Parse(tileDimensionData[1]);
            tileOffset = int.Parse(tileDimensionData[2]);
            System.Diagnostics.Debug.WriteLine("Tile Width: " + tileWidth + "| Tile Height: " + tileHeight + "| Tile Offset: " + tileOffset);

            mapLayer1 = new int[height, width];
            mapLayer2 = new int[height, width];
            mapLayer3 = new int[height, width];
            for (int i = 0; i < height; i++)
            {
                data = buffer.ReadLine();
                String[] mapData = data.Split(' ');
                int index = 0;

                for (int j = 0; j < width; j++)
                {
                    mapLayer1[i, j] = int.Parse(mapData[index]);
                    index++;
                    mapLayer2[i, j] = int.Parse(mapData[index]);
                    index++;
                    mapLayer3[i, j] = int.Parse(mapData[index]);
                    index++;
                }
            }        

            buffer.Close();

        }


        /// <summary>
        /// The tiles are rendered in diamond order /--\
        ///                                          \/
        /// this makes the render process faster than "zig - zag" approach.
        /// </summary>
        /// <param name="renderTarget"></param>
        public void Render(SpriteBatch renderTarget)
        {
            for (int j = 0; j < height; j++)
            {
                for (int i = width-1; i >= 0; i--)
                {
                    int tileValue = mapLayer1[j, i];
                    RenderTile(renderTarget, tileValue, i, j, this.x, this.y);

                    tileValue = mapLayer2[j, i];
                    RenderTile(renderTarget, tileValue, i, j, this.x, this.y);
                }
            }

            // Temporario aki, este layer tem q ser desenhado por ultimo
            // ele deve ficar acima dos personagens
            // assim parece que os personagems passam por tras dos objetos.
            
        }

        /// <summary>
        /// This function may render the upper layer of the map.
        /// This make the characters pass behind tall objects.
        /// </summary>
        /// <param name="renderTarget"></param>
        public void RenderUpperLayer( SpriteBatch renderTarget )
        {
            for (int j = 0; j < height; j++)
            {
                for (int i = width - 1; i >= 0; i--)
                {
                    int tileValue = mapLayer3[j, i];
                    RenderTile(renderTarget, tileValue, i, j, this.x, this.y - tileHeight);
                }
            }
        }



        //***************************************************************************************//
        /// <summary>
        /// Render a tile into screen.
        /// </summary>
        /// <param name="renderTarget"></param> the spriteBach;
        /// <param name="tileValue"></param> tile to take in tileset;
        /// <param name="x"></param> map matrix x;
        /// <param name="y"></param> map matrix y;
        /// <param name="mapX"></param> map position x;
        /// <param name="mapY"></param> map position y;
        private void RenderTile(SpriteBatch renderTarget, int tileValue, int x, int y, float mapX, float mapY )
        {
            int tilex = (tileValue % tilesPerRow) * tileWidth;
            int tiley = (tileValue / tilesPerRow) * tileHeight;

            Rectangle tile = new Rectangle(tilex, tiley, tileWidth, tileHeight);

            float tx = (x * tileWidth / 2) + (y * tileWidth / 2) + mapX;
            float ty = (y * (tileHeight - tileOffset) / 2) - (x * (tileHeight - tileOffset) / 2) + mapY;

            renderTarget.Draw(tileset, new Vector2(tx, ty), tile, Color.White);
        }


        
        private void ResetMap()
        {
            for (int j = 0; j < height; j++)
            {
                for (int i = 0; i < width; i++)
                {
                    this.mapLayer1[j,i] = 1;
                    this.mapLayer2[j, i] = 0;
                    this.mapLayer3[j, i] = 0;
                }
            }
        }


        public int TileWidth
        {
            get { return tileWidth; }
        }

        public int TileHeigth
        {
            get { return tileHeight; }
        }

        public float X
        {
            get { return x; }
        }

        public float Y
        {
            get { return y; }
        }

        public int Height
        {
            get { return height; }
        }

        public int Width
        {
            get { return width; }
        }

        public int[,] getLayer2()
        {
           return mapLayer2;
        }

        public int[,] getLayer1()
        {
            return mapLayer1;
        }

    } // class
} // namespace
